import { Injectable, HttpException, HttpStatus } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto, resetPwdDto } from './dto/update-user.dto';
import { updateProfileDto, updatePwdDto } from './dto/update-profile.dto';
import { QueryUserDto } from './dto/query-user.dto';
import { InjectRepository, InjectEntityManager } from '@nestjs/typeorm';
import { Repository, EntityManager, In } from 'typeorm';
import { User } from './entities/user.entity';
import { Request, Response } from 'express';
import { UserRole } from '../user-role/entities/user-role.entity';
import { UserRoleService } from '../user-role/user-role.service';
import { Workbook } from 'exceljs';
import * as bcrypt from 'bcryptjs';
import { StatusChangeDto } from 'src/common/baseDto/status-change.dto';
import { UserPost } from '../user-post/entities/user-post.entity';
import { UserPostService } from '../user-post/user-post.service';
import * as path from 'path';

@Injectable()
export class UserService {
  constructor(
    @InjectRepository(User) private readonly user: Repository<User>,
    private readonly userRole: UserRoleService,
    private readonly userPost: UserPostService,
    @InjectEntityManager() private readonly entityManager: EntityManager,
  ) {}

  //注册用户
  async create(createUserDto: CreateUserDto) {
    const { username } = createUserDto.user;
    const existUser = await this.user.findOne({
      where: {
        username,
      },
    });
    if (existUser) {
      throw new HttpException('用户名已存在', HttpStatus.BAD_REQUEST);
    }

    try {
      await this.entityManager.transaction(async (manager) => {
        const user = await manager.create(User, createUserDto.user);
        // await manager.insert(UserRole, [
        //   {
        //     user_id: user.id,
        //     role_id: 1, // 默认角色为超级管理员
        //   },
        // ]);
      });
    } catch (err) {
      throw new HttpException('注册失败', HttpStatus.BAD_REQUEST);
    }
  }

  /**
   * 添加用户
   * @param params
   * @param req
   * @returns
   */
  async addUser(params: CreateUserDto, req: Request) {
    let ReqUser = req.user as User;
    params.user.create_by = ReqUser.username;
    try {
      await this.entityManager.transaction(async (manager) => {
        const user = await manager.save(User, params.user);
        if (params.roleIds.length > 0) {
          await manager.insert(
            UserRole,
            params.roleIds.map((k) => {
              return {
                user_id: user.id,
                role_id: k,
              };
            }),
          );
        }
        if (params.postIds.length > 0) {
          await manager.insert(
            UserPost,
            params.postIds.map((k) => {
              return {
                user_id: user.id,
                post_id: k,
              };
            }),
          );
        }
      });
    } catch (err) {
      throw new HttpException('添加用户失败', HttpStatus.BAD_REQUEST);
    }
  }

  /**
   * 用户列表
   * @param query
   * @returns
   */
  async findAll(query: QueryUserDto) {
    let queryBuilder = this.user
      .createQueryBuilder('user')
      .leftJoin('dept', 'dept', 'dept.dept_id = user.dept_id')
      .select(['user.*', 'dept.dept_name dept_name']);
    // 处理查询条件
    if (query.dept_id) {
      queryBuilder = queryBuilder.andWhere('user.dept_id = :deptId', {
        deptId: `${query.dept_id}`,
      });
    }
    if (query.username) {
      queryBuilder = queryBuilder.andWhere('user.username Like :userName', {
        userName: `%${query.username}%`,
      });
    }
    if (query.nickname) {
      queryBuilder = queryBuilder.andWhere('user.nickname LIKE :nickName', {
        nickName: `%${query.nickname}%`,
      });
    }
    if (query.mobile) {
      queryBuilder = queryBuilder.andWhere('user.mobile LIKE :mobile', {
        mobile: `%${query.mobile}%`,
      });
    }
    if (query.status) {
      queryBuilder = queryBuilder.andWhere('user.status  LIKE :status ', {
        status: `${query.status}`,
      });
    }
    if (query.begin_time && query.end_time) {
      queryBuilder = queryBuilder.andWhere(
        'user.create_time BETWEEN :beginTime AND :endTime',
        {
          beginTime: query.begin_time,
          endTime: query.end_time,
        },
      );
    }

    // 处理分页
    if (!query.pageNum || query.pageNum < 1) {
      query.pageNum = 1;
    }
    if (!query.pageSize || query.pageSize < 1) {
      query.pageSize = 10;
    }
    queryBuilder = queryBuilder
      .groupBy('user.id')
      .skip((query.pageNum - 1) * query.pageSize)
      .take(query.pageSize);

    let total = await queryBuilder.getCount();
    let list = await queryBuilder.getRawMany();
    return {
      pageNum: query.pageNum,
      pageSize: query.pageSize,
      total,
      list,
    };
  }

  // 根据用户名查找唯一用户
  async findOneByName(username: string) {
    const existUser = await this.user.findOne({
      where: {
        username,
      },
    });
    return existUser;
  }

  // 查找唯一用户
  async findOne(id: number) {
    let qb = this.user
      .createQueryBuilder('user')
      .leftJoin('user_role', 'userRole', 'user.id = userRole.user_id')
      .leftJoin('user_post', 'userPost', 'user.id = userPost.user_id')
      .select([
        'user.*',
        'GROUP_CONCAT(DISTINCT userRole.role_id) as roleIds',
        'GROUP_CONCAT(DISTINCT userPost.post_id) as postIds',
      ])
      .where('user.id = :id', { id });

    let existUser = await qb.getRawOne();
    return existUser;
  }

  /**
   * 修改用户
   * @param id 用户id
   * @param updateUserDto
   * @param req
   * @returns
   */
  async update(id: number, updateUserDto: UpdateUserDto, req: Request) {
    if (id == 1) {
      throw new HttpException(
        '超级管理员信息不允许修改',
        HttpStatus.BAD_REQUEST,
      );
    }
    let paramsUser = updateUserDto.user;
    let roleIds = updateUserDto.roleIds;
    let postIds = updateUserDto.postIds;
    let reqUser = req.user as User;
    paramsUser.update_by = reqUser.username;
    const existUser = await this.user.update(id, paramsUser);
    if (roleIds) {
      await this.userRole.updateUserRole(id, roleIds);
    }
    if (postIds) {
      await this.userPost.updateUserPost(id, postIds);
    }
    return existUser;
  }

  /**
   * 更新用户状态
   * @param statusChangeDto
   */
  statusChange(statusChangeDto: StatusChangeDto, req: Request) {
    if (statusChangeDto.id == 1) {
      throw new HttpException(
        '超级管理员信息不允许修改',
        HttpStatus.BAD_REQUEST,
      );
    }
    let user = req.user as User;
    return this.user.update(statusChangeDto.id, {
      status: statusChangeDto.status,
      update_by: user.username,
    });
  }

  /**
   * 删除用户
   * @param userIds
   * @returns
   */
  async remove(userIds: number[]) {
    if (userIds.includes(1)) {
      throw new HttpException('超级管理员不允许删除', HttpStatus.BAD_REQUEST);
    }
    try {
      await this.entityManager.transaction(async (manager) => {
        await manager.delete(User, userIds);
        await manager.delete(UserRole, { user_id: In(userIds) });
        await manager.delete(UserPost, { user_id: In(userIds) });
      });
    } catch (err) {
      return err;
    }
  }

  /**
   * 导出为表格
   * @param res
   */
  async exportToExcel(res: Response) {
    const workbook = new Workbook();
    const worksheet = workbook.addWorksheet('用户');

    worksheet.columns = [
      { header: '用户ID', key: 'id', width: 10 },
      { header: '用户名', key: 'username', width: 10 },
      { header: '昵称', key: 'nickname', width: 10 },
      { header: '性别（1：男，2：女,3:未知）', key: 'gender', width: 10 },
      { header: '密码', key: 'password', width: 10 },
      { header: '部门ID', key: 'dept_id', width: 10 },
      { header: '联系方式', key: 'mobile', width: 10 },
      { header: '用户状态（0：正常，1：禁用）', key: 'status', width: 10 },
      { header: '用户邮箱', key: 'email', width: 10 },
      { header: '创建者', key: 'create_by', width: 10 },
      { header: '创建时间', key: 'create_time', width: 10 },
      { header: '更新者', key: 'update_by', width: 10 },
      { header: '更新时间', key: 'update_time', width: 10 },
      { header: '备注', key: 'remark', width: 10 },
    ];

    const data = await this.user.find();
    worksheet.addRows(data);
    res.setHeader(
      'Content-Type',
      'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    );
    let filename = encodeURIComponent('用户.xlsx'); // 这里中文需要转码
    res.setHeader(
      'Content-Disposition',
      'attachment; filename=' + filename + '',
    );
    res.setHeader('Cache-Control', 'max-age=0');
    const file = await workbook.xlsx.writeBuffer();
    res.end(file);
  }

  /**
   * 重置密码
   * @param password 密码
   */
  async resetPwd(dto: resetPwdDto) {
    if (dto.id == 1) {
      throw new HttpException(
        '超级管理员信息不允许修改',
        HttpStatus.BAD_REQUEST,
      );
    }
    const tempUser = await this.user.findOne({ where: { id: dto.id } });
    if (tempUser) {
      tempUser.password = await bcrypt.hashSync(dto.password, 10);
      await this.user.save(tempUser);
      return {
        code: 200,
        message: '密码重置成功',
      };
    } else {
      return {
        code: 400,
        message: '用户不存在',
      };
    }
  }

  /**
   * 下载模版
   * @param res
   */
  async importTemplate(res: Response) {
    const workbook = new Workbook();
    const worksheet = workbook.addWorksheet('用户数据');

    worksheet.columns = [
      { header: '用户ID', key: 'id', width: 10 },
      { header: '用户名', key: 'username', width: 10 },
      { header: '昵称', key: 'nickname', width: 10 },
      { header: '性别（1：男，2：女,3:未知）', key: 'gender', width: 30 },
      { header: '部门ID', key: 'dept_id', width: 10 },
      { header: '联系方式', key: 'mobile', width: 15 },
      { header: '用户状态（0：正常，1：禁用）', key: 'status', width: 30 },
      { header: '用户邮箱', key: 'email', width: 15 },
    ];
    // 遍历表头单元格并设置样式
    worksheet.eachRow({ includeEmpty: true }, function (row, rowNumber) {
      if (rowNumber === 1) {
        // 假设表头在第一行
        row.eachCell({ includeEmpty: true }, function (cell, colNumber) {
          cell.fill = {
            type: 'pattern',
            pattern: 'solid',
            fgColor: { argb: 'FF808080' }, // 灰色填充
          };
          cell.font = {
            name: 'Arial',
            size: 10,
            bold: true,
            color: { argb: 'FFFFFFFF' }, // 白色字体
          };
          cell.alignment = {
            horizontal: 'center', // 水平居中
            vertical: 'middle', // 垂直居中
          };
        });
      }
    });

    res.setHeader(
      'Content-Type',
      'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    );
    let filename = encodeURIComponent('用户模版.xlsx'); // 这里中文需要转码
    res.setHeader(
      'Content-Disposition',
      'attachment; filename=' + filename + '',
    );
    res.setHeader('Cache-Control', 'max-age=0');
    const file = await workbook.xlsx.writeBuffer();
    res.end(file);
  }

  /**
   * 导入数据
   * @param updateSupport
   * @param file
   */
  async importData(updateSupport: string, file: Express.Multer.File) {
    const workbook = new Workbook();
    await workbook.xlsx.load(file.buffer);

    const worksheet = workbook.getWorksheet(1); // 或者使用worksheet.name来获取特定的工作表
    const data: any[] = [];

    worksheet.eachRow({ includeEmpty: true }, function (row, rowNumber) {
      // 跳过标题行（如果有的话）
      if (rowNumber === 1) return;

      const rowData: { [key: string]: any } = {};
      row.eachCell({ includeEmpty: true }, function (cell, colNumber) {
        // 假设你的第一行是标题，并且与列键对应
        if (worksheet.getRow(1).getCell(colNumber).value) {
          rowData[colNumber] = cell.value;
        }
      });
      data.push(rowData);
    });
    let rowDatas = data
      .filter((k) => k['1'])
      .map((k) => {
        return {
          id: k['1'],
          username: k['2'],
          nickname: k['3'],
          gender: k['4'],
          dept_id: k['5'],
          mobile: k['6']?.toString(),
          status: k['7'],
          email: k['8']?.text,
        };
      });
    if (rowDatas.some((k) => k.id == 1)) {
      throw new HttpException('超级管理员信息不允许修改', HttpStatus.OK);
    }
    // 不更新
    if (updateSupport == 'false' || updateSupport == '0') {
      return await this.addUsers(rowDatas);
    }
    // 更新
    else {
      return await this.addUsersAndUpdate(rowDatas);
    }
  }

  /**
   * 添加多个用户
   * @param rowDatas
   */
  async addUsers(rowDatas) {
    try {
      return await this.entityManager.transaction(async (manager) => {
        await manager.insert(User, rowDatas);
        return {
          message: '已添加' + rowDatas.length + '个用户</br>',
        };
      });
    } catch (err) {
      throw new HttpException('添加用户失败:</br>' + err, HttpStatus.OK);
    }
  }

  /**
   * 添加多个用户(含更新)
   * @param rowDatas
   */
  async addUsersAndUpdate(rowDatas) {
    let oldUsers = await this.user.find({
      where: {
        id: In(rowDatas.map((k) => k.id)),
      },
    });
    let inserRows = rowDatas.filter((k) => !oldUsers.some((j) => j.id == k.id));
    let updateRows = rowDatas.filter((k) => oldUsers.some((j) => j.id == k.id));
    try {
      return await this.entityManager.transaction(async (manager) => {
        if (inserRows && inserRows.length > 0) {
          await manager.insert(User, inserRows);
        }
        if (updateRows && updateRows.length > 0) {
          // upsert参数：实体、修改内容、当违反唯一性约束时忽略的字段
          await manager.upsert(User, updateRows, ['id']);
        }
        return {
          message:
            '已添加' +
            inserRows.length +
            '个用户</br>已更新' +
            updateRows.length +
            '个用户',
        };
      });
    } catch (err) {
      throw new HttpException('添加、更新用户失败:</br>' + err, HttpStatus.OK);
    }
  }

  /**
   * 查询用户个人信息
   */
  async getUserProfile(req: Request) {
    let existUser = req.user as User;
    let id = existUser.id;
    let qb = this.user
      .createQueryBuilder('user')
      .leftJoin('user_role', 'userRole', 'user.id = userRole.user_id')
      .leftJoin('user_post', 'userPost', 'user.id = userPost.user_id')
      .leftJoin('role', 'role', 'role.role_id = userRole.role_id')
      .leftJoin('post', 'post', 'post.post_id = userPost.post_id')
      .leftJoin('dept', 'dept', 'dept.dept_id = user.dept_id')
      .select([
        'user.*',
        'dept.dept_name as dept_name',
        'GROUP_CONCAT(DISTINCT role.role_name) as roleNames',
        'GROUP_CONCAT(DISTINCT post.post_name) as postNames',
      ])
      .where('user.id = :id', { id });
    let user = await qb.getRawOne();
    return user;
  }

  /**
   * 修改用户个人信息
   * @param updateProfileDto
   * @param req
   */
  async updateUserProfile(updateProfileDto: updateProfileDto, req: Request) {
    let existUser = req.user as User;
    let id = existUser.id;
    return this.user.update(id, updateProfileDto);
  }

  /**
   * 用户密码重置
   * @param updatePwdDto
   * @param req
   */
  async updatePwd(updatePwdDto: updatePwdDto, req: Request) {
    let existUser = req.user as User;
    let id = existUser.id;
    const userInfo = await this.user
      .createQueryBuilder('user')
      .addSelect('user.password')
      .where('user.id=:id', { id })
      .getOne();
    if (!bcrypt.compareSync(updatePwdDto.oldPassword, userInfo.password)) {
      throw new HttpException('旧密码错误', HttpStatus.BAD_REQUEST);
    }
    let password = await bcrypt.hashSync(updatePwdDto.newPassword, 10);
    await this.user.update(id, { password });
    return {
      message: '用户密码重置成功！',
    };
  }

  /**
   * 用户头像上传
   * @param file
   * @param req
   */
  async uploadAvatar(file: Express.Multer.File, req: Request) {
    let existUser = req.user as User;
    let id = existUser.id;
    let matchRes = path.parse(file.path).dir.match(/images\\(.*)$/);
    let url = null;
    if (matchRes && matchRes.length > 1) {
      url = '/linxi/' + matchRes[1].replace(/\\/g, '/') + '/' + file.filename;
    }
    await this.user.update(id, { avatar: url });
    return {
      imgUrl:url,
      message: '用户头像上传成功',
    };
  }
}
